/** \file
  \brief Implementation of the token reader used to break the expression string up 
  into tokens.

  <pre>
  __________                                 ____  ___
  _____  __ _\______   \_____ _______  ______ __________\   \/  /
  /     \|  |  \     ___/\__  \\_  __ \/  ___// __ \_  __ \     / 
  |  Y Y  \  |  /    |     / __ \|  | \/\___ \\  ___/|  | \/     \
  |__|_|  /____/|____|    (____  /__|  /____  >\___  >__| /___/\  \
  \/                     \/           \/     \/           \_/

  muParserX - A C++ math parser library with array and string support
  Copyright 2010 Ingo Berg

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
  as published by the Free Software Foundation, either version 3 of 
  the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public License
  along with this program.  If not, see http://www.gnu.org/licenses.
  </pre>
  */

#include "mpTokenReader.h"

#include <cassert>

#include "mpParserBase.h"
#include "mpIValReader.h"
#include "mpIfThenElse.h"
#include "mpScriptTokens.h"


MUP_NAMESPACE_START

//---------------------------------------------------------------------------
/** \brief Copy constructor.
  \sa Assign
  \throw nothrow
  */
TokenReader::TokenReader(const TokenReader &a_Reader) 
{ 
  Assign(a_Reader);
}

//---------------------------------------------------------------------------
/** \brief Assignement operator.
  \param a_Reader Object to copy to this token reader.
  \throw nothrow

  Self assignement will be suppressed otherwise #Assign is called.
  */
TokenReader& TokenReader::operator=(const TokenReader &a_Reader) 
{
  if (&a_Reader!=this)
    Assign(a_Reader);

  return *this;
}

//---------------------------------------------------------------------------
/** \brief Assign state of a token reader to this token reader. 
  \param a_Reader Object from which the state should be copied.
  \throw nothrow
  */
void TokenReader::Assign(const TokenReader &obj)
{
  m_pParser             = obj.m_pParser;
  m_sExpr               = obj.m_sExpr;
  m_nPos                = obj.m_nPos;
  m_nNumBra             = obj.m_nNumBra;
  m_nNumIndex           = obj.m_nNumIndex;
  m_nNumIfElse          = obj.m_nNumIfElse;
  m_nSynFlags           = obj.m_nSynFlags;
  m_UsedVar             = obj.m_UsedVar;
  m_pVarDef             = obj.m_pVarDef;
  m_pPostOprtDef        = obj.m_pPostOprtDef;
  m_pInfixOprtDef       = obj.m_pInfixOprtDef;
  m_pOprtDef            = obj.m_pOprtDef;
  m_pFunDef             = obj.m_pFunDef;
  m_pConstDef           = obj.m_pConstDef;
  m_pDynVarShadowValues = obj.m_pDynVarShadowValues;
  m_vTokens             = obj.m_vTokens;

  // Reader klassen klonen 
  DeleteValReader();
  std::size_t i, iSize = obj.m_vValueReader.size();
  for (i=0; i<iSize; ++i)
  {
    m_vValueReader.push_back(obj.m_vValueReader[i]->Clone(this));
  }
}

//---------------------------------------------------------------------------
/** \brief Constructor. 

  Create a Token reader and bind it to a parser object. 

  \pre [assert] a_pParser may not be NULL
  \post #m_pParser==a_pParser
  \param a_pParent Parent parser object of the token reader.
  */
  TokenReader::TokenReader(ParserXBase *a_pParent)
  :m_pParser(a_pParent)
  ,m_sExpr()
  ,m_nPos(0)
  ,m_nNumBra(0)
  ,m_nNumIndex(0)
  ,m_nNumIfElse(0)
  ,m_nSynFlags(0)
  ,m_vTokens()
  ,m_eLastTokCode(cmUNKNOWN)
  ,m_pFunDef(NULL)
  ,m_pOprtDef(NULL)
  ,m_pInfixOprtDef(NULL)
  ,m_pPostOprtDef(NULL)
  ,m_pConstDef(NULL)
  ,m_pDynVarShadowValues(NULL)
  ,m_pVarDef(NULL)
  ,m_vValueReader()
  ,m_UsedVar()
   ,m_fZero(0)
{
  assert(m_pParser);
  SetParent(m_pParser);
}

//---------------------------------------------------------------------------
/** \brief Destructor (trivial).

  \throw nothrow
  */
TokenReader::~TokenReader()
{
  DeleteValReader();
}

//---------------------------------------------------------------------------
void TokenReader::DeleteValReader()
{
  int iSize = (int)m_vValueReader.size();
  for (int i=0; i<iSize; ++i)
    delete m_vValueReader[i];

  m_vValueReader.clear();
}

//---------------------------------------------------------------------------
/** \brief Create instance of a ParserTokenReader identical with this 
  and return its pointer. 

  This is a factory method the calling function must take care of the object destruction.

  \return A new ParserTokenReader object.
  \throw nothrow
  */
TokenReader* TokenReader::Clone(ParserXBase *a_pParent) const
{
  std::auto_ptr<TokenReader> ptr(new TokenReader(*this));
  ptr->SetParent(a_pParent);
  return ptr.release();
}

//---------------------------------------------------------------------------
void TokenReader::AddValueReader(IValueReader *a_pReader)
{
  a_pReader->SetParent(this);
  m_vValueReader.push_back(a_pReader);
}

//---------------------------------------------------------------------------
void TokenReader::AddSynFlags(int flag)
{
  m_nSynFlags |= flag;
}

//---------------------------------------------------------------------------
const TokenReader::token_buf_type& TokenReader::GetTokens() const
{
  return m_vTokens;
}

//---------------------------------------------------------------------------
/** \brief Return the current position of the token reader in the formula string. 

  \return #m_nPos
  \throw nothrow
  */
int TokenReader::GetPos() const
{
  return m_nPos;
}

//---------------------------------------------------------------------------
void TokenReader::ClearExpr() 
{
  this->m_sExpr.clear();
}

//---------------------------------------------------------------------------

const string_type TokenReader::GetExprAsString() const
{
  return convert_expr_to_string(m_sExpr);
}

//---------------------------------------------------------------------------
/** \brief Return a reference to the formula. 

  \return #m_sExpr
  \throw nothrow
  */
const token_list & TokenReader::GetExpr() const
{
  return m_sExpr;
}

//---------------------------------------------------------------------------
/** \brief Return a map containing the used variables only. */
const var_maptype& TokenReader::GetUsedVar() const
{
  return m_UsedVar;
}

//---------------------------------------------------------------------------
/** \brief Initialize the token Reader. 

  Sets the expression position index to zero and set Syntax flags to 
  default for initial parsing. 
  */
void TokenReader::SetExpr(const token_list &a_sFormula)
{
  m_sExpr = a_sFormula;
  m_vTokens.clear();
  ReInit();
}

//---------------------------------------------------------------------------
/** \brief Reset the token reader to the start of the formula. 
  \post #m_nPos==0, #m_nSynFlags = noOPT | noBC | noPOSTOP | noSTR
  \throw nothrow
  \sa ESynCodes

  The syntax flags will be reset to a value appropriate for the 
  start of a formula.
  */
void TokenReader::ReInit()
{
  m_nPos = 0;
  m_nNumBra = 0;
  m_nNumIndex = 0;
  m_nNumIfElse = 0;
  m_nSynFlags = noOPT | noBC | noPFX | noCOMMA | noIO | noIC | noIF | noELSE;
  m_UsedVar.clear();
  m_eLastTokCode = cmUNKNOWN;
}

//---------------------------------------------------------------------------
const ptr_tok_type& TokenReader::Store(const ptr_tok_type &t, int token_pos)
{
  m_eLastTokCode = t->GetCode();
  t->SetExprPos(token_pos);
  m_vTokens.push_back(t);
  return t;
}

//---------------------------------------------------------------------------
/** \brief Read the next token from the string. */ 
ptr_tok_type TokenReader::ReadNextToken()
{
  assert(m_pParser);
  //    const char_type *szFormula = m_sExpr.c_str();

  int token_pos = m_nPos;

  ptr_tok_type pTok;

  // Check for end of expression
  if (IsEOF(pTok))    
    return Store(pTok, token_pos); 

  if ( !(m_nSynFlags & noOPT) && IsOprt(pTok))       
    return Store(pTok, token_pos); // Check for user defined binary operator

  if ( !(m_nSynFlags & noIFX) && IsInfixOpTok(pTok)) 
    return Store(pTok, token_pos); // Check for unary operators

  if (IsValTok(pTok))     
    return Store(pTok, token_pos); // Check for values / constant tokens

  if (IsBuiltIn(pTok))
    return Store(pTok, token_pos); // Check built in operators / tokens

  if (IsVarOrConstTok(pTok))     
    return Store(pTok, token_pos); // Check for variable tokens

  if (IsFunTok(pTok))     
    return Store(pTok, token_pos);

  if ( !(m_nSynFlags & noPFX) && IsPostOpTok(pTok))  
    return Store(pTok, token_pos); // Check for unary operators

  // 2.) We have found no token, maybe there is a token that we don't expect here.
  //     Again call the Identifier functions but this time only those we don't expect 
  //     to find.
  if ( (m_nSynFlags & noOPT) && IsOprt(pTok))        
    return Store(pTok, token_pos); // Check for user defined binary operator

  if ( (m_nSynFlags & noIFX) && IsInfixOpTok(pTok))  
    return Store(pTok, token_pos); // Check for unary operators

  if ( (m_nSynFlags & noPFX) && IsPostOpTok(pTok))   
    return Store(pTok, token_pos); // Check for unary operators
  // </ibg>

  // Now we are in trouble because there is something completely unknown....

  // Check the string for an undefined variable token. This is done 
  // only if a flag is set indicating to ignore undefined variables.
  // This is a way to conditionally avoid an error if undefined variables 
  // occur. The GetExprVar function must supress the error for undefined 
  // variables in order to collect all variable names including the 
  // undefined ones.
  if ( (m_pParser->m_bIsQueryingExprVar || m_pParser->m_bAutoCreateVar) && IsUndefVarTok(pTok) )  
    return Store(pTok, token_pos);

  // Check for unknown token
  // 
  // !!! From this point on there is no exit without an exception possible...
  // 
  const string_type & sTok = this->m_sExpr[m_nPos];

  ErrorContext err;
  err.Errc  = ecUNASSIGNABLE_TOKEN;
  err.Expr  = this->GetExprAsString(); //m_sExpr;
  err.Pos   = m_nPos;
  err.Ident = sTok;

  throw ParserError(err);
}

//---------------------------------------------------------------------------
void TokenReader::SetParent(ParserXBase *a_pParent)
{
  m_pParser             =  a_pParent; 
  m_pFunDef             = &a_pParent->m_FunDef;
  m_pOprtDef            = &a_pParent->m_OprtDef;
  m_pInfixOprtDef       = &a_pParent->m_InfixOprtDef;
  m_pPostOprtDef        = &a_pParent->m_PostOprtDef;
  m_pVarDef             = &a_pParent->m_VarDef;
  m_pConstDef           = &a_pParent->m_valConst;
  m_pDynVarShadowValues = &a_pParent->m_valDynVarShadow;
}

//---------------------------------------------------------------------------
/** \brief Check if a built in operator or other token can be found.
*/
bool TokenReader::IsBuiltIn(ptr_tok_type &a_Tok)
{
  const char_type **pOprtDef = m_pParser->GetOprtDef();
  const string_type & token = m_sExpr[m_nPos];
  int i;

  try
  {
    // Compare token with function and operator strings
    // check string for operator/function
    for (i=0; pOprtDef[i]; i++)
    {
      if ( token == string_type(pOprtDef[i]) )
      {
        switch(i)
        {
          case cmARG_SEP:
            if (m_nSynFlags & noCOMMA)
              throw ecUNEXPECTED_COMMA;

            m_nSynFlags = noBC | noOPT | noEND | noNEWLINE | noCOMMA | noPFX | noIC | noIO | noIF | noELSE;
            a_Tok = ptr_tok_type(new GenericToken((ECmdCode)i, pOprtDef[i]));
            break;

          case cmELSE:
            if (m_nSynFlags & noELSE)
              throw ecUNEXPECTED_CONDITIONAL;

            m_nNumIfElse--;
            if (m_nNumIfElse<0)
              throw ecMISPLACED_COLON;

            m_nSynFlags = noBC | noIO | noIC | noPFX | noEND | noNEWLINE | noCOMMA | noOPT | noIF | noELSE;
            a_Tok = ptr_tok_type(new TokenIfThenElse(cmELSE));
            break;

          case cmIF:
            if (m_nSynFlags & noIF)
              throw ecUNEXPECTED_CONDITIONAL;

            m_nNumIfElse++; 
            m_nSynFlags = noBC | noIO | noPFX | noIC | noEND | noNEWLINE | noCOMMA | noOPT | noIF | noELSE;
            a_Tok = ptr_tok_type(new TokenIfThenElse(cmIF));
            break;

          case cmBO:
            if (m_nSynFlags & noBO)
              throw ecUNEXPECTED_PARENS;

            if (m_eLastTokCode==cmFUNC)
              m_nSynFlags = noOPT | noEND | noNEWLINE | noCOMMA | noPFX | noIC | noIO | noIF | noELSE;
            else
              m_nSynFlags = noBC | noOPT | noEND | noNEWLINE | noCOMMA | noPFX | noIC | noIO | noIF | noELSE;

            m_nNumBra++;
            a_Tok = ptr_tok_type(new GenericToken((ECmdCode)i, pOprtDef[i]));
            break;

          case cmBC:   
            if (m_nSynFlags & noBC)
              throw ecUNEXPECTED_PARENS;

            m_nSynFlags  = noBO | noVAR | noVAL | noFUN | noIFX | noIO;
            m_nNumBra--;

            if (m_nNumBra<0)
              throw ecUNEXPECTED_PARENS;

            a_Tok = ptr_tok_type(new GenericToken((ECmdCode)i, pOprtDef[i]));
            break;

          case cmIO:
            if (m_nSynFlags & noIO)
              throw ecUNEXPECTED_SQR_BRACKET;

            m_nSynFlags  = noIC | noIO | noOPT | noPFX | noBC | noNEWLINE;
            m_nNumIndex++;
            a_Tok = ptr_tok_type(new GenericToken((ECmdCode)i, pOprtDef[i]));
            break;

          case cmIC:
            if (m_nSynFlags & noIC)
              throw ecUNEXPECTED_SQR_BRACKET;

            m_nSynFlags  = noBO | noIFX;
            m_nNumIndex--;

            if (m_nNumIndex<0)
              throw ecUNEXPECTED_SQR_BRACKET;

            a_Tok = ptr_tok_type(new GenericToken((ECmdCode)i, pOprtDef[i]));
            break;

          default:  // The operator is listed in c_DefaultOprt, but not here. This is a bad thing...
            throw ecINTERNAL_ERROR;
        } // switch operator id

        m_nPos++; // += 1; // (int)len;
        return true;
      } // if operator string found
    } // end of for all operator strings
  }
  catch (EErrorCodes e)
  {
    ErrorContext err;
    err.Errc  = e;
    err.Expr  = this->GetExprAsString(); // m_sExpr;
    err.Ident = pOprtDef[i];
    err.Pos   = m_nPos;
    throw ParserError(err);
  }

  return false;
}

//---------------------------------------------------------------------------
/** \brief Check for End of expression
*/
bool TokenReader::IsEOF(ptr_tok_type &a_Tok)
{
  bool bRet(false);
  try
  {
    if ( m_sExpr.size() > 0 && m_nPos>=(int)m_sExpr.size())
    {
      if ( m_nSynFlags & noEND )
        throw ecUNEXPECTED_EOF;

      if (m_nNumBra>0)
        throw ecMISSING_PARENS;

      if (m_nNumIndex>0)
        throw ecMISSING_SQR_BRACKET;

      if (m_nNumIfElse>0)
        throw ecMISSING_ELSE_CLAUSE;

      m_nSynFlags = 0;
      a_Tok = ptr_tok_type(new GenericToken(cmEOE));
      bRet = true;
    }
  }
  catch(EErrorCodes e)
  {
    ErrorContext err;
    err.Errc = e;
    err.Ident = _T("");
    err.Expr = this->GetExprAsString(); //m_sExpr;
    err.Pos = m_nPos;
    throw ParserError(err);
  }

  return bRet;
}

//---------------------------------------------------------------------------
/** \brief Check if a string position contains a unary infix operator. 
  \return true if a function token has been found false otherwise.
  */
bool TokenReader::IsInfixOpTok(ptr_tok_type &a_Tok)
{
  const string_type & sTok = this->m_sExpr[ m_nPos ];
  try
  {
    // iteraterate over all infix operator strings
    // the match needs to be to the operator that is longest (i.e. --var should match -- not -)
    size_t msize = 0;
    oprt_ifx_multimap::const_iterator match = m_pInfixOprtDef->begin();
    oprt_ifx_multimap::const_iterator item = m_pInfixOprtDef->begin();
    if( m_pInfixOprtDef->count( sTok )  > 0 )
    {
      item = m_pInfixOprtDef->find( sTok );
      const size_t size = item->first.length();
      if(size > msize)
      {
        msize = size;
        match = item;
      }
    }
    if( msize > 0 )
    {
      a_Tok = match->second;
      m_nPos += 1;// (int)match->first.length();

      if (m_nSynFlags & noIFX)
        throw ecUNEXPECTED_OPERATOR;

      m_nSynFlags = noPFX | noIFX | noOPT | noBC | noIC | noIO | noEND | noCOMMA | noNEWLINE; 
      return true;
    }
    return false;
  }
  catch(EErrorCodes e)
  {
    ErrorContext err;
    err.Errc = e;
    err.Pos = m_nPos;
    err.Ident = a_Tok->GetIdent();
    err.Expr = this->GetExprAsString(); // m_sExpr;
    throw ParserError(err);
  }
}


//---------------------------------------------------------------------------
/** \brief Check expression for function tokens. */
bool TokenReader::IsFunTok(ptr_tok_type &a_Tok)
{
  if (m_pFunDef->size()==0)
    return false;

  const string_type & sTok = this->m_sExpr[ m_nPos ];

  try
  {
    fun_multimap::iterator item = m_pFunDef->find(sTok);
    if (item==m_pFunDef->end())
      return false;

    m_nPos++; //  = (int)iEnd;
    a_Tok = item->second;
    a_Tok->Compile(_T("xxx"));

    if (m_nSynFlags & noFUN)
      throw ecUNEXPECTED_FUN;

    m_nSynFlags = sfALLOW_NONE ^ noBO;
    return true;
  }
  catch(EErrorCodes e)
  {
    ErrorContext err;
    err.Errc = e;
    err.Pos = m_nPos - (int)a_Tok->GetIdent().length();
    err.Ident = a_Tok->GetIdent();
    err.Expr = this->GetExprAsString(); // m_sExpr;
    throw ParserError(err);
  }
}

//---------------------------------------------------------------------------
/** \brief Check if a string position contains a unary post value operator. */
bool TokenReader::IsPostOpTok(ptr_tok_type &a_Tok)
{
  // Tricky problem with equations like "3m+5":
  //     m is a postfix operator, + is a valid sign for postfix operators and 
  //     for binary operators parser detects "m+" as operator string and 
  //     finds no matching postfix operator.
  // 
  // This is a special case so this routine slightly differs from the other
  // token readers.

  // Test if there could be a postfix operator
  const string_type & sTok = this->m_sExpr[m_nPos];

  try
  {
    // iteraterate over all postfix operator strings
    oprt_pfx_multimap::const_iterator item;
    for (item=m_pPostOprtDef->begin(); item!=m_pPostOprtDef->end(); ++item)
    {
      if (sTok.find(item->first)!=0)
        continue;

      a_Tok = item->second;
      m_nPos += 1; // (int)item->first.length();

      if (m_nSynFlags & noPFX)
        throw ecUNEXPECTED_OPERATOR;

      m_nSynFlags = noVAL | noVAR | noFUN | noBO | noPFX | noIO;
      return true;
    }

    return false;
  }
  catch(EErrorCodes e)
  {
    ErrorContext err;
    err.Errc = e;
    err.Pos = m_nPos - (int)a_Tok->GetIdent().length();
    err.Ident = a_Tok->GetIdent();
    err.Expr = this->GetExprAsString(); // m_sExpr;
    throw ParserError(err);
  }
}

//---------------------------------------------------------------------------
/** \brief Check if a string position contains a binary operator. */
bool TokenReader::IsOprt(ptr_tok_type &a_Tok)
{
  const string_type & sTok = this->m_sExpr[m_nPos];

  try
  {
    // Note:
    // All tokens in oprt_bin_multimap are have been sorted by their length
    // Long operators must come first! Otherwise short names (like: "add") that
    // are part of long token names (like: "add123") will be found instead 
    // of the long ones.
    // Length sorting is done with ascending length so we use a reverse iterator here.
    if( m_pOprtDef->count( sTok ) > 0 )
    {

      // operator found, check if we expect one...
      if (m_nSynFlags & noOPT) 
      {
        // An operator was found but is not expected to occur at
        // this position of the formula, maybe it is an infix 
        // operator, not a binary operator. Both operator types
        // can use the same characters in their identifiers.
        if (IsInfixOpTok(a_Tok))
          return true;

        // nope, it's no infix operator and we dont expect 
        // an operator
        throw ecUNEXPECTED_OPERATOR;
      }
      else
      {
        // we do not yet know which overloaded operator is the correct
        // one to bind to, so we assign a dummy for now
        a_Tok = ptr_tok_type( m_pOprtDef->find( sTok )->second->Clone());

        m_nPos ++; // = (int)a_Tok->GetIdent().length(); 
        m_nSynFlags  = noBC | noIO | noIC | noOPT | noCOMMA | noEND | noNEWLINE | noPFX;
        return true;
      }
    }
    return false;
  }
  catch(EErrorCodes e)
  {
    ErrorContext err;
    err.Errc = e;
    err.Pos = m_nPos; // - (int)item->first.length();
    err.Ident = m_pOprtDef->find(sTok)->first;
    err.Expr = this->GetExprAsString(); //  m_sExpr;
    throw ParserError(err);
  }
}

//---------------------------------------------------------------------------
/** \brief Check whether the token at a given position is a value token.

  Value tokens are either values or constants.

  \param a_Tok [out] If a value token is found it will be placed here.
  \return true if a value token has been found.
  */
bool TokenReader::IsValTok(ptr_tok_type &a_Tok)
{
  if (m_vValueReader.size()==0)
    return false;

  const string_type & sTok = m_sExpr[m_nPos];

  try
  {
    // call the value recognition functions provided by the user
    // Call user defined value recognition functions
    int iSize = (int)m_vValueReader.size();
    Value val;
    for (int i=0; i<iSize; ++i)
    {
      if ( m_vValueReader[i]->IsValue(sTok.c_str(), val) )
      {
        if (m_nSynFlags & noVAL)
          throw ecUNEXPECTED_VAL;

        m_nSynFlags = noVAL | noVAR | noFUN | noBO | noIFX | noIO;
        a_Tok = ptr_tok_type(val.Clone());
        a_Tok->SetIdent( sTok );
        m_nPos ++;
        return true;
      }
    }
  }
  catch(EErrorCodes e)
  {
    ErrorContext err;
    err.Errc = e;
    err.Pos = m_nPos;
    err.Ident = sTok;
    err.Expr = this->GetExprAsString(); // m_sExpr;
    err.Pos = m_nPos - (int)sTok.length();
    throw ParserError(err);
  }

  return false;
}

//---------------------------------------------------------------------------
/** \brief Check wheter a token at a given position is a variable token. 
  \param a_Tok [out] If a variable token has been found it will be placed here.
  \return true if a variable token has been found.
  */
bool TokenReader::IsVarOrConstTok(ptr_tok_type &a_Tok)
{
  if (!m_pVarDef->size() && !m_pConstDef->size() )
    return false;

  const string_type & sTok = this->m_sExpr[m_nPos];
  try
  {
    // Check for variables
    var_maptype::const_iterator item =  m_pVarDef->find(sTok);
    if (item!=m_pVarDef->end())
    {
      if (m_nSynFlags & noVAR)
        throw ecUNEXPECTED_VAR;

      m_nPos ++; //  = iEnd;
      m_nSynFlags = noVAL | noVAR | noFUN | noBO | noIFX;
      a_Tok = item->second;
      a_Tok->SetIdent(sTok);
      m_UsedVar[item->first] = item->second;  // Add variable to used-var-list
      return true;
    }

    // Check for constants
    item = m_pConstDef->find(sTok);
    if (item!=m_pConstDef->end())
    {
      if (m_nSynFlags & noVAL)
        throw ecUNEXPECTED_VAL;

      m_nPos ++; //  = iEnd;
      m_nSynFlags = noVAL | noVAR | noFUN | noBO | noIFX | noIO;
      a_Tok = item->second;
      a_Tok->SetIdent(sTok);
      return true;
    }

    return false;
  }
  catch(EErrorCodes e)
  {
    ErrorContext err;
    err.Errc = e;
    err.Pos = m_nPos;
    err.Ident = sTok;
    err.Expr = this->GetExprAsString(); // m_sExpr;
    throw ParserError(err);
  }

  return true;
}

//---------------------------------------------------------------------------
bool TokenReader::IsComment()
{
  return false;
}

//---------------------------------------------------------------------------
/** \brief Check wheter a token at a given position is an undefined variable. 
  \param a_Tok [out] If a variable tom_pParser->m_vStringBufken has been found it will be placed here.
  \return true if a variable token has been found.
  \throw nothrow
  */
bool TokenReader::IsUndefVarTok(ptr_tok_type &a_Tok)
{
  const string_type & sTok = this->m_sExpr[ m_nPos ];

  if (m_nSynFlags & noVAR)
  {
    ErrorContext err;
    err.Errc = ecUNEXPECTED_VAR;
    err.Ident = sTok;
    err.Expr = this->GetExprAsString(); // m_sExpr;
    err.Pos = m_nPos - (int)sTok.length();
    throw ParserError(err);
  }

  // Create a variable token
  if (m_pParser->m_bAutoCreateVar)
  {
    ptr_val_type val(new Value);                   // Create new value token
    m_pDynVarShadowValues->push_back(val);         // push to the vector of shadow values 
    a_Tok = ptr_tok_type(new Variable(val.Get())); // bind variable to the new value item
    (*m_pVarDef)[sTok] = a_Tok;                    // add new variable to the variable list
  }
  else
    a_Tok = ptr_tok_type(new Variable(NULL));      // bind variable to empty variable

  a_Tok->SetIdent(sTok);
  m_UsedVar[sTok] = a_Tok;     // add new variable to used-var-list

  m_nPos ++; // =  iEnd;
  m_nSynFlags = noVAL | noVAR | noFUN | noBO | noIFX;
  return true;
}
} // namespace mu
